#include "vimview.h"
#include <gdk/gdkkeysyms.h>
#include <gdk/gdkx.h>
#include <libexif/exif-data.h>
//#include <exif-utils.h>
#include <libexif/exif-loader.h>
#include <string.h>

/*
 * Local prototypes
 */
int	    imgLoadProgress		    ( Imlib_Image   im,
					      char	    percent,
					      int	    update_x,
					      int	    update_y,
					      int	    update_w,
					      int	    update_h );
int	    imgSetWindowBackground	    ();
int	    imgRotate			    ();

/*
 * Functions
 */

/*
 * Marks the current background we have as "stale". This function should be
 * called before all resize requests (since the resize request might not
 * succeed).
 */
void
imgSetBGStateStale()
{
    if( img.pmap != None )
    {
	XFreePixmap( v.dpy, img.pmap );
	img.pmap = None;
    }

    if( img.fullImg != None )
    {
	XFreePixmap( v.dpy, img.fullImg );
	img.fullImg = None;
    }

    img.wantRefresh = 1;
}

/* Set img.clip to the full image */
inline void
imgResetClip()
{
    img.clip.x	    = 0;
    img.clip.y	    = 0;
    img.clip.width  = img.width;
    img.clip.height = img.height;
}

/*
 * Sets zoom, rend, clip so that the original image is scaled to fit inside the
 * displayed window.
 */
void
imgSetZoomToFitWinSize( int winWidth, int winHeight )
{
    imgResetClip();

    if( img.width * winHeight < img.height * winWidth )
    {
	img.zoom	= (float) winHeight / img.height;
	img.rend.height	= winHeight;
	img.rend.width	= img.width * img.zoom;
    }
    else
    {
	img.zoom	= (float) winWidth / img.width;
	img.rend.width	= winWidth;
	img.rend.height = img.height * img.zoom;
    }

    img.rend.x = ( winWidth - img.rend.width ) / 2;
    img.rend.y = ( winHeight - img.rend.height ) / 2;
}

void
imgResizeWindowToImage()
{
    assert( img.width && img.height );

    GdkScreen	*screen;
    int		maxWidth, maxHeight;
    
    screen	= gtk_widget_get_screen( img.win );
    maxWidth	= gdk_screen_get_width( screen ) * v.maxWinSize / 100;
    maxHeight	= gdk_screen_get_height( screen ) * v.maxWinSize / 100;

    if( img.width * img.zoom > maxWidth || img.height * img.zoom > maxHeight )
    {
	imgSetZoomToFitWinSize( maxWidth, maxHeight );

	img.rend.x	= 0;
	img.rend.y	= 0;
	img.winWidth	= img.rend.width;
	img.winHeight	= img.rend.height;
    }
    else
    {
	imgResetClip();

	img.rend.x	= 0;
	img.rend.y	= 0;
	img.winWidth	= img.width * img.zoom + .5;
	img.winHeight	= img.height * img.zoom + .5;
	img.rend.width	= img.winWidth;
	img.rend.height = img.winHeight;
    }

    imgSetBGStateStale();
    debug( DBG_WARN, "Requesting new window size %dx%d. Might fail if either"
	    " the window width or height is unchanged.",
	    img.winWidth, img.winHeight );

    //gdk_display_sync( gtk_widget_get_display( img.win ) );
    gtk_window_resize( GTK_WINDOW(img.win), img.winWidth,
        		img.winHeight );
}

void
imgSetClipOffsets()
{
    int newClipWidth, newClipHeight;

    gtk_window_get_size( GTK_WINDOW(img.win), &img.winWidth,
			    &img.winHeight );

    /* Set clipwidth and offsets to display only part of the image */
    if( img.width * img.zoom < img.winWidth )
    {
	img.rend.width = img.width * img.zoom;
	img.rend.x = (img.winWidth - img.rend.width) / 2;
    }
    else
    {
	img.rend.width = img.winWidth;
	img.rend.x = 0;
    }

    if( img.height * img.zoom < img.winHeight )
    {
	img.rend.height = img.height * img.zoom;
	img.rend.y = (img.winHeight - img.rend.height) / 2;
    }
    else
    {
	img.rend.height = img.winHeight;
	img.rend.y = 0;
    }

    /* Set up clip so that the center of the rendered image is not moved */
    newClipWidth	= img.rend.width / img.zoom;
    newClipHeight	= img.rend.height / img.zoom;

    img.clip.x += (img.clip.width - newClipWidth) / 2;
    img.clip.y += (img.clip.height - newClipHeight) / 2;
    img.clip.width	= newClipWidth;
    img.clip.height	= newClipHeight;

    if( img.clip.x < 0 ) img.clip.x = 0;
    if( img.clip.y < 0 ) img.clip.y = 0;

    if( img.clip.x + img.clip.width > img.width )
	img.clip.x = img.width - img.clip.width;
    if( img.clip.y + img.clip.height > img.height )
	img.clip.y = img.height - img.clip.height;
}


/*
 * Callback function when loading the main image. This creates img.pmap, and
 * sets it as the imlib drawable.
 */
int imgLoadProgress( Imlib_Image im,
			    char	percent,
			    int		update_x,
			    int		update_y,
			    int		update_w,
			    int		update_h )
{
    debug( DBG_FUNCTRACE, "%s( %p, %hd, %d, %d, %d, %d )", __func__,
	    im, percent, update_x, update_y, update_w, update_h );

    static Window   win;

    static int draw_x, draw_y, draw_w, draw_h;

    /* First time progress function is called for this image */
    if( img.loading == 0 )
    {
	img.loading = 1;

	imlib_context_set_image(im);

	img.width	= imlib_image_get_width();
	img.height	= imlib_image_get_height();

	if( img.zoom != 0. )
	{
	    img.fitImageOnWinResize = FALSE;
	    imgSetClipOffsets();
	}

	else if( v.fitImage )
	{
	    img.fitImageOnWinResize = TRUE;
	    gtk_window_get_size( GTK_WINDOW(img.win), &img.winWidth,
				    &img.winHeight );
	    imgSetZoomToFitWinSize( img.winWidth, img.winHeight );
	}

	else
	{
	    img.fitImageOnWinResize = TRUE;
	    img.zoom = 1;
	    imgResizeWindowToImage();
	    img.rend.x = img.rend.y = 0;
	}

	gtk_widget_show( img.win );

	win = GDK_WINDOW_XID( img.win->window );

	if( img.pmap != None )
	    XFreePixmap( v.dpy, img.pmap );
	img.pmap = XCreatePixmap( v.dpy, win, img.winWidth,
				     img.winHeight, v.depth );

	/* Create GC with default values for XCopyArea */
	if( img.gc == None )
	{
	    XGCValues gcvalues;
	    gcvalues.foreground = v.defaultBG;
	    gcvalues.graphics_exposures = False;
	    img.gc = XCreateGC( v.dpy, img.pmap,
		    GCForeground | GCGraphicsExposures, &gcvalues );
	}

	/* Default background on window */
	XFillRectangle( v.dpy, img.pmap, img.gc, 0, 0,
		img.winWidth, img.winHeight );
	XFillRectangle( v.dpy, win, img.gc, 0, 0,
		img.winWidth, img.winHeight );

	imlib_context_set_display( v.dpy );
	imlib_context_set_visual( v.vis );
	imlib_context_set_colormap( v.cmap );
	imlib_context_set_drawable( img.pmap );

	imlib_context_set_anti_alias(0); /* TODO */
	imlib_context_set_dither(0);
	imlib_context_set_blend(1);

	draw_x = update_x * img.zoom;
	draw_y = update_y * img.zoom;
    }

    draw_w = (int) ((update_x + update_w) * img.zoom) -
		(int) (update_x * img.zoom);
    draw_h = (int) ((update_y + update_h) * img.zoom) -
		(int) (update_y * img.zoom);

    /*
     * See if the updated region intersects the region we would show on screen
     */
    if( img.fitImageOnWinResize )
    {
	imlib_render_image_part_on_drawable_at_size( update_x, update_y,
		update_w, update_h, draw_x + img.rend.x, draw_y + img.rend.y,
		draw_w, draw_h );
	XCopyArea( v.dpy, img.pmap, win, img.gc,
		draw_x + img.rend.x, draw_y + img.rend.y, draw_w, draw_h,
		draw_x + img.rend.x, draw_y + img.rend.y );
    }

    debug( DBG_DEBUG, "Filled rectangle %d, %d, %d, %d",
	    draw_x, draw_y, draw_w, draw_h );

    if( update_x + update_w >= img.width )
    {
	draw_y += draw_h;
	draw_x = 0;
    }
    else
    {
	/* Should not be reached */
	assert(0);
	draw_x += draw_w;
    }

    if( update_x + update_w >= img.width && update_y + update_h >= img.height )
    {
	/* Last update */
	debug( DBG_DEBUG, "Last update" );
    }

    return 1;
}

gint
imgDeleteEvent( GtkWidget *widget, GdkEvent *event, gpointer data )
{
    /*
     * Free all resources we created
     */
    if( img.gc != None )
    {
	XFreeGC( v.dpy, img.gc );
	img.gc = None;
    }

    if( img.pmap != None )
    {
	XFreePixmap( v.dpy, img.pmap );
	img.pmap = None;
    }

    if( img.image )
    {
	imlib_context_set_image( img.image );
	imlib_free_image();
	img.image = NULL;
    }

    return(FALSE);
}


void
imgDestroyEvent( GtkWidget *widget, gpointer data )
{
    gtk_main_quit();
}


gboolean
imgConfigureEvent( GtkWidget *widget, GdkEventConfigure *ev, gpointer data)
{
    debug( DBG_FUNCTRACE, "%s() - new size: %dx%d, old_size %dx%d",
	    __func__, ev->width, ev->height, img.winWidth, img.winHeight );

    assert( widget == img.win );
    assert( ev->height && ev->width );

    if( img.winWidth == ev->width && img.winHeight == ev->height )
	return TRUE;

    /* Save new window size */
    img.winWidth = ev->width;
    img.winHeight = ev->height;

    if( !img.loading && img.image )
    {
	debug( DBG_DEBUG, "Resizing image" );

	imgSetBGStateStale();

	if( img.fitImageOnWinResize )
	    imgSetZoomToFitWinSize( ev->width, ev->height );
	else
	    imgSetClipOffsets();

	imgSetWindowBackground();
    }
    return TRUE;
}


#if 0
gboolean
imgDragBegin( GtkWidget *widget, GdkDragContext dc, gpointer data )
{
    assert( widget == img.win );

    gtk_drag_source_set_icon();
}
#endif


int
imgPan( int xdist, int ydist )
{
    int moved = 0;

    if( xdist < 0 && img.clip.x > 0 )
    {
	moved = 1;
	img.clip.x = max( img.clip.x + xdist, 0 );
    }
    else if( xdist > 0 && img.clip.x + img.clip.width < img.width )
    {
	moved = 1;
	img.clip.x = min( img.clip.x + xdist,
			    img.width - img.clip.width );
    }

    if( ydist < 0 && img.clip.y > 0 )
    {
	moved = 1;
	img.clip.y = max( img.clip.y + ydist, 0 );
    }
    else if( ydist > 0 && img.clip.y + img.clip.height < img.height )
    {
	moved = 1;

	img.clip.y = min( img.clip.y + ydist,
			    img.height - img.clip.height );
    }

    return moved;
}

void
imgFastUpdateWindowBG( int setPmap )
{
    debug( DBG_FUNCTRACE, "%s( setPmap=%d )", __func__, setPmap );

    int	    swidth, sheight;
    Window  win = GDK_WINDOW_XID( img.win->window );

    swidth = img.width * img.zoom;
    sheight = img.height * img.zoom;

    if( img.fullImg == None )
    {
	img.fullImg = XCreatePixmap( v.dpy, win,
		swidth, sheight, v.depth );
	imlib_context_set_drawable( img.fullImg );
	imlib_render_image_on_drawable_at_size( 0, 0, swidth, sheight );
	imlib_context_set_drawable( img.pmap );
    }

    debug( DBG_DEBUG, "clip.x=%d, clip.y=%d, zoom=%.1f, rend.x=%d, rend.y=%d",
	    img.clip.x, img.clip.y, img.zoom, img.rend.x, img.rend.y );

    XCopyArea( v.dpy, img.fullImg, win, img.gc,
	    img.clip.x * img.zoom, img.clip.y * img.zoom,
	    img.rend.width, img.rend.height,
	    img.rend.x, img.rend.y );

    if( setPmap )
    {
	if( img.rend.width < img.winWidth || img.rend.height < img.winHeight )
	    XFillRectangle( v.dpy, img.pmap, img.gc, 0, 0, swidth, sheight );

	XCopyArea( v.dpy, img.fullImg, img.pmap, img.gc,
		img.clip.x * img.zoom, img.clip.y * img.zoom,
		img.rend.width, img.rend.height,
		img.rend.x, img.rend.y );

	XSetWindowBackgroundPixmap( v.dpy, win, img.pmap );
	XClearWindow( v.dpy, win );
    }
}


gboolean
imgKeyEvent( GtkWidget *widget, GdkEventKey *ev, gpointer data )
{
    assert( widget == img.win );
    
    if( ev->type == GDK_KEY_PRESS )
    {
	switch( ev->keyval )
	{
	    case GDK_Q:
	    case GDK_q:
		imgDestroyEvent( img.win, NULL );
		break;

	    case GDK_j:
	    case GDK_J:
	    case GDK_k:
	    case GDK_K:
	    case GDK_l:
	    case GDK_L:
	    case GDK_h:
	    case GDK_H:
		if( !img.fitImageOnWinResize )
		{
		    int xdist = 0, ydist = 0;
		    int factor;

		    switch( ev->keyval )
		    {
			case GDK_j:
			case GDK_J:
			    ydist = 1;
			    break;

			case GDK_k:
			case GDK_K:
			    ydist = -1;
			    break;

			case GDK_h:
			case GDK_H:
			    xdist = -1;
			    break;

			case GDK_l:
			case GDK_L:
			    xdist = 1;
			    break;

			default:
			    assert(0);
		    }

		    if( ev->state & GDK_SHIFT_MASK )
			factor = 4;
		    else if( ev->state & GDK_CONTROL_MASK )
			factor = 50;
		    else
			factor = 10;

		    xdist *= img.width/factor;
		    ydist *= img.height/factor;

		    if( imgPan( xdist, ydist ) )
			imgSetWindowBackground();
		}
		break;

	    case GDK_f:		/* Full screen */
	    case GDK_F:
		debug( DBG_DEBUG, "state=0x%x, flags=0x%x",
			GTK_WIDGET_STATE(img.win), GTK_WIDGET_FLAGS(img.win) );
		if( img.fullscreen )
		    gtk_window_unfullscreen( GTK_WINDOW(img.win) );
		else
		    gtk_window_fullscreen( GTK_WINDOW(img.win) );
		img.fullscreen = ~img.fullscreen;
		break;

	    case GDK_plus:	/* Zoom in / out */
	    case GDK_equal:
	    case GDK_minus:
		if( ev->keyval == GDK_minus )
		    img.zoom /= 1.5;
		else
		    img.zoom *= 1.5;

		img.fitImageOnWinResize = FALSE;
		imgSetClipOffsets();
		imgSetWindowBackground();
		break;

	    case GDK_bracketleft:
	    case GDK_bracketright:
		img.orientation =
		    (ev->keyval == GDK_bracketleft ? BOT_LEFT : TOP_RIGHT );
		imgRotate();
		/* imgRotate already called imgSetBGStateStale */
		gtk_window_resize( GTK_WINDOW(img.win), img.winHeight,
				    img.winWidth );
		break;

	    case GDK_1:
		img.fitImageOnWinResize = FALSE;
		img.zoom = 1.;
		imgSetClipOffsets();
		imgSetWindowBackground();
		break;

	    case GDK_x:	    /* Fit image to window (preserving aspect) */
	    case GDK_X:
		img.fitImageOnWinResize = TRUE;
		imgSetZoomToFitWinSize( img.winWidth, img.winHeight );
		imgSetWindowBackground();
		break;

	    case GDK_w:	    /* Fit window to image (preserving zoom) */
	    case GDK_W:
		imgResizeWindowToImage();
		XClearWindow( v.dpy, GDK_WINDOW_XID( img.win->window ) );
		break;

	    default:
		return FALSE;
	}
	return TRUE;
    }
    else
	return FALSE;
}


gboolean
imgClickEvent( GtkWidget *widget, GdkEventButton *ev, gpointer data )
{
    debug( DBG_FUNCTRACE, "%s(). x=%.1f, y=%.1f, state=0x%x, type=0x%x",
	    __func__, ev->x, ev->y, ev->state, ev->type);

    if( img.fitImageOnWinResize )
	return FALSE;

    if( ev->type == GDK_BUTTON_PRESS && ev->button == 1 )
    {
	img.moving = 1;
	img.clickx = ev->x;
	img.clicky = ev->y;
    }

    else if( ev->type == GDK_BUTTON_RELEASE && ev->button == 1 )
    {
	img.moving = 0;

	imgFastUpdateWindowBG( 1 ); /* Also sets the background pixmap */
	XFreePixmap( v.dpy, img.fullImg );
	img.fullImg = None;
    }

    return TRUE;
}

gboolean
imgMoveEvent( GtkWidget *widget, GdkEventMotion *ev, gpointer data )
{
    debug( DBG_FUNCTRACE, "%s(). x=%f, y=%f, state=%u", __func__,
	    ev->x, ev->y, ev->state);

    if( !img.moving )
	return FALSE;

    if( imgPan( (img.clickx - ev->x)/img.zoom, (img.clicky - ev->y)/img.zoom ) )
    {
	debug( DBG_DEBUG, "Moved from (%f, %f) to (%f, %f)",
		img.clickx, img.clicky, ev->x, ev->y );
	img.clickx = ev->x;
	img.clicky = ev->y;

	imgFastUpdateWindowBG(0);
    }
    return TRUE;
}

gboolean
imgExpose( GtkWidget *widget, GdkEventExpose *ev, gpointer data )
{
    debug( DBG_FUNCTRACE, "%s()", __func__ );

    if( img.wantRefresh )
    {
#if 0
	int width, height;

	gtk_window_get_size( GTK_WINDOW( img.win ), &width, &height );
	if( width != img.winWidth || height != img.winHeight )
	{
	    debug( DBG_TMP, "Sizes differ in expose event"
		    " (Old %dx%d, new %dx%d)", img.winWidth, img.winHeight,
		    width, height );
	    //gtk_window_resize( GTK_WINDOW( img.win ), img.winWidth,
	    //        img.winHeight );
	    return FALSE;
	}
#endif

	if( img.fitImageOnWinResize )
	    imgSetZoomToFitWinSize( img.winWidth, img.winHeight );
	imgSetWindowBackground();
    }

    return TRUE;
}

void
imgCreateWin( const char *filename )
{
    assert( img.win == NULL );

    /*
     * Create image window
     */
    img.win = gtk_window_new( GTK_WINDOW_TOPLEVEL );
    gtk_widget_realize( img.win );

    if( GTK_WIDGET_NO_WINDOW( img.win ) )
	die( "Could not create image window" );

    if( v.geomstring )
	gtk_window_parse_geometry( GTK_WINDOW(img.win), v.geomstring );

    /* Tell GTK we're going to manage the widget painting and background */
    gtk_widget_set_app_paintable( img.win, TRUE );
    gtk_widget_set_double_buffered( img.win, FALSE );
    gdk_window_set_back_pixmap( img.win->window, NULL, FALSE );

    /* Signal / event handlers */
    gtk_signal_connect( GTK_OBJECT( img.win ), "delete_event",
	    GTK_SIGNAL_FUNC( imgDeleteEvent ), NULL );
    gtk_signal_connect( GTK_OBJECT (img.win), "destroy",
	    GTK_SIGNAL_FUNC (imgDestroyEvent), NULL );
    g_signal_connect( img.win, "configure_event",
	    G_CALLBACK( imgConfigureEvent ), NULL );
    gtk_signal_connect( GTK_OBJECT( img.win ), "key_press_event",
	    GTK_SIGNAL_FUNC( imgKeyEvent ), NULL );
    gtk_signal_connect( GTK_OBJECT( img.win ), "motion_notify_event",
	    GTK_SIGNAL_FUNC( imgMoveEvent ), NULL );
    g_signal_connect( img.win, "button_press_event",
	    G_CALLBACK( imgClickEvent ), NULL );
    g_signal_connect( img.win, "button_release_event",
	    G_CALLBACK( imgClickEvent ), NULL );

    gtk_signal_connect( GTK_OBJECT( img.win ), "expose_event",
	    GTK_SIGNAL_FUNC( imgExpose ), NULL );

    gtk_widget_add_events( img.win,
	    GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK
	    | GDK_BUTTON_RELEASE_MASK );
}

void
imgGetExifOrientation( const char *filename )
{
    debug( DBG_DEBUG, "%s( filename=%s )", __func__, filename );

    ExifData	*data;
    ExifEntry	*entry;
    char	val[32];

    if( (data = exif_data_new_from_file( filename )) == NULL )
	return;

    if(
	 ( entry = exif_content_get_entry( data->ifd[EXIF_IFD_0],
	    EXIF_TAG_ORIENTATION ) ) == NULL
      )
	goto UnrefDataAndReturn;

    exif_entry_get_value( entry, val, sizeof(val) );

    if( !strncmp( "top - right", val, sizeof( val ) ) )
	img.orientation = TOP_RIGHT;
    else if( !strncmp( "left - bottom", val, sizeof( val ) ) )
	img.orientation = BOT_LEFT;
    else
	img.orientation = TOP_LEFT;

    debug( DBG_DEBUG, "val=%.32s, orientation=%d", val, img.orientation );

UnrefDataAndReturn:
    exif_data_unref( data );
}

/* Rotate (if necessary) based on Exif information */
int
imgRotate()
{
    imlib_context_set_image( img.image );

    switch( img.orientation )
    {
	case TOP_RIGHT:
	    imlib_image_orientate( 1 );
	    break;

	case BOT_LEFT:
	    imlib_image_orientate( 3 );
	    break;

	default:
	    return 0; /* No rotation */
    }

    /*
     * Rotation was performed. Swap all x & y values and resize windows /
     * pixmaps
     */
    swap( img.width, img.height );
    swap( img.clip.x, img.clip.y );
    swap( img.clip.width, img.clip.height );
    swap( img.rend.x, img.rend.y );
    swap( img.rend.width, img.rend.height );

    //swap( img.clickx, img.clicky ); /* Probably unnecessary */
    imgSetBGStateStale();
    return 1; /* Rotated */
}

int
imgShow( const char *file )
{
    assert( file );
    if( img.win == NULL )
    {
	imgInit();
	imgCreateWin( file );
    }

    imlib_context_set_progress_function( imgLoadProgress );
    imlib_context_set_progress_granularity( 3 );

    if( img.image )
    {
	imlib_context_set_image( img.image );
	imlib_free_image();
    }
    img.image = imlib_load_image( file );

    img.loading = 0; /* Set by progress function, so needs to be reset */

    imlib_context_set_progress_function( NULL );
    if( img.image == NULL )
    {
	errorMessage( "Error loading file %s", file );
	return 0;
    }

    imgGetExifOrientation( file );
    if( imgRotate() )
    {
	if( img.fitImageOnWinResize )
	{
	    img.zoom = 1;
	    imgResizeWindowToImage();
	}
	else
	    /* imgRotate already called imgSetBGStateStale */
	    gtk_window_resize( GTK_WINDOW(img.win), img.winHeight,
		    img.winWidth );
    }
    else
	imgSetWindowBackground();

    return img.image ? 1 : 0;
}


void
imgInit()
{
    /* Initialize values in img */
    img.zoom	= v.defaultZoom;
    img.pmap	= None;

    img.fullImg = None;
    img.moving	= 0;
}


/*
 * Sets the window background.
 */
int
imgSetWindowBackground()
{
    debug( DBG_FUNCTRACE, "%s()", __func__ );

    assert( img.image );

    Window win	= GDK_WINDOW_XID( img.win->window );

    /*
     * Re render the image with anti-alias enabled.
     */
    if( img.pmap == None )
    {
	img.pmap = XCreatePixmap( v.dpy, GDK_WINDOW_XID(img.win->window),
		img.winWidth, img.winHeight, v.depth );
	imlib_context_set_drawable( img.pmap );
    }

    XFillRectangle( v.dpy, img.pmap, img.gc,
			0, 0, img.winWidth, img.winHeight );
    imlib_context_set_image( img.image );
    imlib_context_set_anti_alias( 1 );

    debug( DBG_DEBUG, "Re-rendering image with blend=%d, aa=%d",
	    imlib_context_get_blend(), imlib_context_get_anti_alias() );
    if( img.fitImageOnWinResize )
    {
	imlib_render_image_on_drawable_at_size( img.rend.x, img.rend.y,
		img.rend.width, img.rend.height );
    }
    else
    {
	imlib_render_image_part_on_drawable_at_size(
		img.clip.x, img.clip.y, img.clip.width, img.clip.height,
		img.rend.x, img.rend.y, img.rend.width, img.rend.height );
    }
    XSetWindowBackgroundPixmap( v.dpy, win, img.pmap );
    XClearWindow( v.dpy, win );

    img.wantRefresh = 0;
    return 1; /* TODO: Trap error value */
}
